#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
游戏按键录制与回放系统 - 主录制模块

功能：
- 多屏幕窗口截图
- 高精度按键录制
- 结构化数据存储

作者: GitHub Copilot
版本: 2.0
"""

import os
import time
import argparse
import json
import threading
from datetime import datetime
from typing import List, Optional, Tuple, Dict, Any

import psutil
from PIL import ImageGrab
import ctypes
from ctypes import wintypes

# ============================================================================
# Windows API 初始化
# ============================================================================

user32 = ctypes.windll.user32
dwmapi = ctypes.windll.dwmapi
kernel32 = ctypes.windll.kernel32
try:
    shcore = ctypes.windll.shcore
except Exception:
    shcore = None

# ============================================================================
# 常量定义
# ============================================================================

# 窗口状态常量
SW_RESTORE = 9
SW_SHOW = 5
DWMWA_CLOAKED = 14

# 按键录制相关常量
WH_KEYBOARD_LL = 13
WH_MOUSE_LL = 14
WM_KEYDOWN = 0x0100
WM_KEYUP = 0x0101
WM_SYSKEYDOWN = 0x0104
WM_SYSKEYUP = 0x0105
WM_LBUTTONDOWN = 0x0201
WM_LBUTTONUP = 0x0202
WM_RBUTTONDOWN = 0x0204
WM_RBUTTONUP = 0x0205
WM_MBUTTONDOWN = 0x0207
WM_MBUTTONUP = 0x0208
WM_MOUSEMOVE = 0x0200
WM_MOUSEWHEEL = 0x020A

# ============================================================================
# 函数类型定义
# ============================================================================

EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, wintypes.HWND, wintypes.LPARAM)
HookProc = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_int, wintypes.WPARAM, wintypes.LPARAM)

# Windows API 函数定义
GetWindowTextW = user32.GetWindowTextW
GetWindowTextLengthW = user32.GetWindowTextLengthW
IsWindowVisible = user32.IsWindowVisible
GetWindowRect = user32.GetWindowRect
SetForegroundWindow = user32.SetForegroundWindow
ShowWindow = user32.ShowWindow
GetWindowThreadProcessId = user32.GetWindowThreadProcessId
GetCursorPos = user32.GetCursorPos
GetAsyncKeyState = user32.GetAsyncKeyState

# ============================================================================
# 数据结构定义
# ============================================================================

class RECT(ctypes.Structure):
    """Windows RECT 结构"""
    _fields_ = [("left", ctypes.c_long),
                ("top", ctypes.c_long),
                ("right", ctypes.c_long),
                ("bottom", ctypes.c_long)]

class POINT(ctypes.Structure):
    """Windows POINT 结构"""
    _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)]

class KBDLLHOOKSTRUCT(ctypes.Structure):
    """键盘底层钩子结构"""
    _fields_ = [("vkCode", wintypes.DWORD),
                ("scanCode", wintypes.DWORD),
                ("flags", wintypes.DWORD),
                ("time", wintypes.DWORD),
                ("dwExtraInfo", ctypes.POINTER(wintypes.ULONG))]

class MSLLHOOKSTRUCT(ctypes.Structure):
    """鼠标底层钩子结构"""
    _fields_ = [("pt", POINT),
                ("mouseData", wintypes.DWORD),
                ("flags", wintypes.DWORD),
                ("time", wintypes.DWORD),
                ("dwExtraInfo", ctypes.POINTER(wintypes.ULONG))]

# ============================================================================
# 系统工具函数
# ============================================================================

def set_dpi_awareness():
    """避免高分屏缩放导致坐标不准"""
    try:
        if shcore:
            shcore.SetProcessDpiAwareness(2)  # Per Monitor v2
        else:
            user32.SetProcessDPIAware()
    except Exception:
        pass

def is_admin():
    """检查是否以管理员权限运行"""
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

def run_as_admin():
    """重新以管理员权限运行程序"""
    if is_admin():
        return True
    else:
        import sys
        print("⚠️ 按键录制功能需要管理员权限")
        print("🔄 正在尝试以管理员权限重新运行...")
        try:
            ctypes.windll.shell32.ShellExecuteW(
                None, 
                "runas", 
                sys.executable, 
                " ".join(sys.argv), 
                None, 
                1
            )
            return False  # 当前进程应该退出
        except:
            print("❌ 无法获取管理员权限，按键录制功能将不可用")
            return False

def get_virtual_screen_bounds():
    """获取虚拟屏幕的边界（包括所有显示器）"""
    try:
        # 获取虚拟屏幕的边界
        left = user32.GetSystemMetrics(76)    # SM_XVIRTUALSCREEN
        top = user32.GetSystemMetrics(77)     # SM_YVIRTUALSCREEN  
        width = user32.GetSystemMetrics(78)   # SM_CXVIRTUALSCREEN
        height = user32.GetSystemMetrics(79)  # SM_CYVIRTUALSCREEN
        
        return left, top, left + width, top + height
    except Exception:
        return 0, 0, 1920, 1080  # 默认值

# ============================================================================
# 按键录制核心类
# ============================================================================

class KeyRecorder:
    """
    按键录制器 - 使用轮询方式检测按键状态
    
    特性：
    - 高精度轮询（10ms间隔）
    - 完整修饰键状态记录
    - 鼠标位置同步记录
    - 线程安全操作
    """
    
    def __init__(self, window_hwnd=None, window_title=None):
        """初始化录制器"""
        self.events = []
        self.start_time = None
        self.recording = False
        self.lock = threading.Lock()
        self.polling_thread = None
        self.key_states = {}  # 记录按键状态
        self.mouse_pos = (0, 0)  # 记录鼠标位置
        self.window_hwnd = window_hwnd  # 目标窗口句柄
        self.window_title = window_title  # 目标窗口标题
        
        # 监控的按键虚拟键码映射
        self.monitor_keys = {
            # 移动键
            'W': 0x57, 'A': 0x41, 'S': 0x53, 'D': 0x44,
            # 功能键
            'SPACE': 0x20, 'SHIFT': 0x10, 'CTRL': 0x11, 'ALT': 0x12,
            # 系统键
            'ESC': 0x1B, 'ENTER': 0x0D, 'TAB': 0x09,
            # 鼠标按键
            'LEFT_MOUSE': 0x01, 'RIGHT_MOUSE': 0x02, 'MIDDLE_MOUSE': 0x04
        }
    """按键录制器 - 使用轮询方式检测按键状态"""
    def __init__(self, window_hwnd=None, window_title=None):
        self.events = []
        self.start_time = None
        self.recording = False
        self.lock = threading.Lock()
        self.polling_thread = None
        self.key_states = {}  # 记录按键状态
        self.mouse_pos = (0, 0)  # 记录鼠标位置
        self.window_hwnd = window_hwnd  # 目标窗口句柄
        self.window_title = window_title  # 目标窗口标题
        
        # 常用按键的虚拟键码
        self.monitor_keys = {
            'W': 0x57, 'A': 0x41, 'S': 0x53, 'D': 0x44,
            'SPACE': 0x20, 'SHIFT': 0x10, 'CTRL': 0x11, 'ALT': 0x12,
            'ESC': 0x1B, 'ENTER': 0x0D, 'TAB': 0x09,
            'LEFT_MOUSE': 0x01, 'RIGHT_MOUSE': 0x02, 'MIDDLE_MOUSE': 0x04
        }
    
    def start_recording(self):
        """开始录制"""
        self.recording = True
        self.start_time = time.time()
        self.events = []
        self.key_states = {}
        
        # 启动轮询线程
        self.polling_thread = threading.Thread(target=self._polling_loop, daemon=True)
        self.polling_thread.start()
        
        print("🎮 开始录制按键（轮询模式）...")
        print("💡 监控按键: W, A, S, D, 空格, Shift, Ctrl, Alt, ESC, Enter, Tab")
        print("💡 监控鼠标: 左键, 右键, 中键, 移动")
        return True
    
    def stop_recording(self):
        """停止录制"""
        self.recording = False
        if self.polling_thread:
            self.polling_thread.join(timeout=1.0)
        print(f"🛑 停止录制，共记录 {len(self.events)} 个事件")
    
    def _polling_loop(self):
        """轮询检测按键状态"""
        while self.recording:
            try:
                current_time = time.time() - self.start_time
                
                # 检测键盘按键
                for key_name, vk_code in self.monitor_keys.items():
                    if key_name.endswith('_MOUSE'):
                        continue  # 鼠标按键单独处理
                    
                    current_state = bool(user32.GetAsyncKeyState(vk_code) & 0x8000)
                    previous_state = self.key_states.get(key_name, False)
                    
                    if current_state != previous_state:
                        self.key_states[key_name] = current_state
                        
                        # 获取当前鼠标位置（按键时的鼠标位置也很重要）
                        point = POINT()
                        user32.GetCursorPos(ctypes.byref(point))
                        
                        with self.lock:
                            event = {
                                "type": "keyboard",
                                "timestamp": current_time,
                                "absolute_time": time.time(),
                                "action": "down" if current_state else "up",
                                "key_name": key_name,
                                "key_code": vk_code,
                                "mouse_position": {"x": point.x, "y": point.y},
                                "modifiers": self._get_modifier_state(),
                                "sequence_id": len(self.events)
                            }
                            self.events.append(event)
                            print(f"🎹 {key_name} {'按下' if current_state else '释放'} @({point.x},{point.y})")
                
                # 检测鼠标按键
                for mouse_key, vk_code in [('LEFT_MOUSE', 0x01), ('RIGHT_MOUSE', 0x02), ('MIDDLE_MOUSE', 0x04)]:
                    current_state = bool(user32.GetAsyncKeyState(vk_code) & 0x8000)
                    previous_state = self.key_states.get(mouse_key, False)
                    
                    if current_state != previous_state:
                        self.key_states[mouse_key] = current_state
                        
                        # 获取当前鼠标位置
                        point = POINT()
                        user32.GetCursorPos(ctypes.byref(point))
                        
                        with self.lock:
                            event = {
                                "type": "mouse",
                                "timestamp": current_time,
                                "absolute_time": time.time(),
                                "action": f"{mouse_key.lower().replace('_mouse', '')}_{'down' if current_state else 'up'}",
                                "button": mouse_key.lower().replace('_mouse', ''),
                                "x": point.x,
                                "y": point.y,
                                "modifiers": self._get_modifier_state(),
                                "sequence_id": len(self.events)
                            }
                            self.events.append(event)
                            mouse_name = mouse_key.replace('_MOUSE', '').lower()
                            print(f"🖱️ {mouse_name}键 {'按下' if current_state else '释放'} at ({point.x}, {point.y})")
                
                # 检测鼠标移动（降低频率）
                if len(self.events) % 50 == 0:  # 每50次轮询检测一次鼠标移动
                    point = POINT()
                    user32.GetCursorPos(ctypes.byref(point))
                    if (point.x, point.y) != self.mouse_pos:
                        old_pos = self.mouse_pos
                        self.mouse_pos = (point.x, point.y)
                        with self.lock:
                            event = {
                                "type": "mouse",
                                "timestamp": current_time,
                                "absolute_time": time.time(),
                                "action": "move",
                                "x": point.x,
                                "y": point.y,
                                "delta_x": point.x - old_pos[0],
                                "delta_y": point.y - old_pos[1],
                                "modifiers": self._get_modifier_state(),
                                "sequence_id": len(self.events)
                            }
                            self.events.append(event)
                
                time.sleep(0.01)  # 10ms 轮询间隔
                
            except Exception as e:
                print(f"❌ 轮询异常: {e}")
                break
    
    def _get_modifier_state(self):
        """获取修饰键状态"""
        return {
            "shift": bool(user32.GetAsyncKeyState(0x10) & 0x8000),
            "ctrl": bool(user32.GetAsyncKeyState(0x11) & 0x8000),
            "alt": bool(user32.GetAsyncKeyState(0x12) & 0x8000),
            "win": bool(user32.GetAsyncKeyState(0x5B) & 0x8000)
        }
    
    def save_events(self, file_path: str):
        """保存事件到文件"""
        with self.lock:
            # 添加更多元数据用于回放
            data = {
                "recording_info": {
                    "start_time": self.start_time,
                    "end_time": time.time(),
                    "total_duration": time.time() - self.start_time if self.start_time else 0,
                    "recording_method": "polling",
                    "sample_rate": "10ms",
                    "screen_resolution": get_virtual_screen_bounds(),
                    "recorded_at": datetime.now().isoformat(),
                    "window_info": {
                        "title": self.window_title,
                        "hwnd": hex(self.window_hwnd) if self.window_hwnd else None
                    }
                },
                "events": self.events,
                "statistics": {
                    "total_events": len(self.events),
                    "keyboard_events": len([e for e in self.events if e["type"] == "keyboard"]),
                    "mouse_events": len([e for e in self.events if e["type"] == "mouse"]),
                    "key_press_count": len([e for e in self.events if e["type"] == "keyboard" and e["action"] == "down"]),
                    "mouse_click_count": len([e for e in self.events if e["type"] == "mouse" and "down" in e["action"]])
                },
                "key_mapping": {
                    "W": {"description": "向前移动", "vk_code": 0x57},
                    "A": {"description": "向左移动", "vk_code": 0x41},
                    "S": {"description": "向后移动", "vk_code": 0x53},
                    "D": {"description": "向右移动", "vk_code": 0x44},
                    "SPACE": {"description": "跳跃/确认", "vk_code": 0x20},
                    "SHIFT": {"description": "奔跑/修饰键", "vk_code": 0x10},
                    "CTRL": {"description": "蹲下/控制", "vk_code": 0x11},
                    "ALT": {"description": "特殊动作", "vk_code": 0x12},
                    "ESC": {"description": "菜单/取消", "vk_code": 0x1B},
                    "ENTER": {"description": "确认", "vk_code": 0x0D},
                    "TAB": {"description": "切换", "vk_code": 0x09}
                }
            }
            
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=2, ensure_ascii=False)
            
            print(f"📝 按键记录已保存: {file_path}")
            print(f"📊 统计: {data['statistics']['total_events']} 个事件, 录制时长: {data['recording_info']['total_duration']:.2f}秒")
    
    def get_event_count(self) -> int:
        """获取事件数量"""
        with self.lock:
            return len(self.events)

# ============================================================================
# 窗口管理函数
# ============================================================================

def is_window_cloaked(hwnd: int) -> bool:
    """检查UWP窗口是否被隐藏（cloaked）"""
    is_cloaked = wintypes.DWORD()
    hr = dwmapi.DwmGetWindowAttribute(
        hwnd, DWMWA_CLOAKED, ctypes.byref(is_cloaked), ctypes.sizeof(is_cloaked)
    )
    if hr != 0:
        return False
    return bool(is_cloaked.value)

def get_window_title(hwnd: int) -> str:
    length = GetWindowTextLengthW(hwnd)
    buf = ctypes.create_unicode_buffer(length + 1)
    GetWindowTextW(hwnd, buf, length + 1)
    return buf.value.strip()

def hwnd_to_pid(hwnd: int) -> int:
    pid = wintypes.DWORD()
    GetWindowThreadProcessId(hwnd, ctypes.byref(pid))
    return pid.value

def enum_windows() -> List[int]:
    hwnds = []
    def cb(hwnd, _):
        if IsWindowVisible(hwnd) and not is_window_cloaked(hwnd):
            if get_window_title(hwnd):
                hwnds.append(hwnd)
        return True
    user32.EnumWindows(EnumWindowsProc(cb), 0)
    return hwnds

def list_windows():
    rows = []
    for hwnd in enum_windows():
        title = get_window_title(hwnd)
        pid = hwnd_to_pid(hwnd)
        try:
            pname = psutil.Process(pid).name()
        except Exception:
            pname = "N/A"
        rows.append((hex(hwnd), pid, pname, title))
    rows.sort(key=lambda x: (x[2].lower(), x[3].lower()))
    print(f"{'HWND':>12}  {'PID':>7}  {'Process':<28}  Title")
    print("-" * 100)
    for hwnd_hex, pid, pname, title in rows:
        print(f"{hwnd_hex:>12}  {pid:>7}  {pname:<28}  {title}")

def find_hwnd_by_title(keyword: str) -> Optional[int]:
    kw = keyword.lower()
    # 优先挑选"标题更长"的匹配，通常更具体
    candidates = []
    for hwnd in enum_windows():
        title = get_window_title(hwnd)
        if kw in title.lower():
            candidates.append((len(title), hwnd))
    if not candidates:
        return None
    candidates.sort(reverse=True)
    return candidates[0][1]

def bring_to_front(hwnd: int):
    # 先尝试恢复窗口（如果是最小化状态）
    ShowWindow(hwnd, SW_RESTORE)
    time.sleep(0.1)
    
    # 显示窗口
    ShowWindow(hwnd, SW_SHOW)
    time.sleep(0.1)
    
    # 设置为前台窗口
    SetForegroundWindow(hwnd)
    time.sleep(0.3)  # 增加等待时间，确保窗口完全刷新
    
    # 再次尝试设置前台（有时需要多次尝试）
    SetForegroundWindow(hwnd)
    time.sleep(0.2)

def get_window_rect(hwnd: int) -> Optional[Tuple[int, int, int, int]]:
    rect = RECT()
    if GetWindowRect(hwnd, ctypes.byref(rect)):
        return rect.left, rect.top, rect.right, rect.bottom
    return None

def is_window_really_visible(hwnd: int) -> bool:
    """检查窗口是否真正可见（不被遮挡且有实际内容）"""
    if not IsWindowVisible(hwnd):
        return False
    
    if is_window_cloaked(hwnd):
        return False
    
    rect = get_window_rect(hwnd)
    if not rect:
        return False
    
    l, t, r, b = rect
    # 检查窗口大小是否合理
    if (r - l) < 10 or (b - t) < 10:
        return False
    
    return True

# ============================================================================
# 截图相关函数
# ============================================================================

def screenshot_window_safe(hwnd: int, save_path: str, verbose: bool = False) -> bool:
    """安全的窗口截图，返回是否成功"""
    try:
        # 确保窗口可见
        if not is_window_really_visible(hwnd):
            if verbose:
                print(f"⚠ 窗口不可见，尝试重新激活...")
            bring_to_front(hwnd)
            time.sleep(0.5)
            
            if not is_window_really_visible(hwnd):
                if verbose:
                    print(f"❌ 窗口仍然不可见")
                return False
        
        rect = get_window_rect(hwnd)
        if not rect:
            if verbose:
                print(f"❌ 无法获取窗口矩形区域")
            return False
            
        l, t, r, b = rect
        if verbose:
            print(f"📐 窗口坐标: ({l}, {t}) - ({r}, {b}), 大小: {r-l}x{b-t}")
        
        # 获取虚拟屏幕信息
        v_left, v_top, v_right, v_bottom = get_virtual_screen_bounds()
        if verbose:
            print(f"🖥️ 虚拟屏幕范围: ({v_left}, {v_top}) - ({v_right}, {v_bottom})")
        
        # 尝试多种截图方法
        img = None
        
        # 方法1: 多屏幕全屏截图后裁剪（支持多显示器）
        try:
            if verbose:
                print("🖥️ 尝试多屏幕截图...")
            # 使用 all_screens=True 来截取所有屏幕
            full_img = ImageGrab.grab(all_screens=True)
            
            # 获取全屏幕图像的尺寸
            full_width, full_height = full_img.size
            if verbose:
                print(f"🖥️ 全屏幕尺寸: {full_width}x{full_height}")
                print(f"📐 窗口坐标: ({l}, {t}) - ({r}, {b})")
            
            # 在多屏幕环境下，需要将窗口坐标转换为相对于全屏截图的坐标
            # 虚拟屏幕的左上角可能不是 (0,0)
            offset_x = l - v_left
            offset_y = t - v_top
            crop_left = offset_x
            crop_top = offset_y
            crop_right = offset_x + (r - l)
            crop_bottom = offset_y + (b - t)
            
            if verbose:
                print(f"🎯 转换后的裁剪坐标: ({crop_left}, {crop_top}) - ({crop_right}, {crop_bottom})")
            
            # 确保裁剪坐标在有效范围内
            crop_left = max(0, min(crop_left, full_width))
            crop_top = max(0, min(crop_top, full_height))
            crop_right = max(0, min(crop_right, full_width))
            crop_bottom = max(0, min(crop_bottom, full_height))
            
            if verbose:
                print(f"🔧 调整后的裁剪坐标: ({crop_left}, {crop_top}) - ({crop_right}, {crop_bottom})")
            
            if crop_right > crop_left and crop_bottom > crop_top:
                img = full_img.crop((crop_left, crop_top, crop_right, crop_bottom))
                if verbose:
                    print("✅ 使用多屏幕截图裁剪成功")
                
                # 检查是否是纯黑图像
                extrema = img.convert('L').getextrema()
                if extrema == (0, 0):  # 纯黑图像
                    if verbose:
                        print("⚠ 截图为纯黑，可能窗口被遮挡")
            else:
                if verbose:
                    print("❌ 裁剪坐标无效")
                img = None
                
        except Exception as e:
            if verbose:
                print(f"⚠ 多屏幕截图失败: {e}")
        
        # 如果截图成功，保存文件
        if img is not None:
            # 确保目录存在
            os.makedirs(os.path.dirname(save_path), exist_ok=True)
            img.save(save_path, "PNG")
            if verbose:
                print(f"✅ 截图已保存: {save_path}")
            
            return True
        else:
            if verbose:
                print(f"❌ 截图失败")
            return False
            
    except Exception as e:
        if verbose:
            print(f"❌ 截图过程出错: {e}")
        return False

def run_screenshot_loop(hwnd: int, interval: float, picture_dir: str, record_keys: bool = False):
    """运行截图循环"""
    # 获取窗口标题用于文件夹命名
    title = get_window_title(hwnd)
    print(f"🎯 开始截图循环，目标窗口: {title}")
    
    # 创建以时间戳命名的文件夹
    timestamp = datetime.now().strftime("%H%M%S")
    session_dir = os.path.join(picture_dir, timestamp)
    os.makedirs(session_dir, exist_ok=True)
    print(f"📁 截图保存目录: {session_dir}")
    
    # 初始化按键录制器
    key_recorder = None
    if record_keys:
        key_recorder = KeyRecorder(window_hwnd=hwnd, window_title=title)
        if not key_recorder.start_recording():
            print("❌ 按键录制初始化失败，将只进行截图")
            key_recorder = None
    
    # 先测试一张截图（详细日志）
    test_path = os.path.join(session_dir, "test.png")
    print("🧪 测试截图...")
    if not screenshot_window_safe(hwnd, test_path, verbose=True):
        print("❌ 测试截图失败，请检查窗口状态")
        if key_recorder:
            key_recorder.stop_recording()
        return
    
    print("✅ 测试截图成功，准备开始录制...")
    
    # 3秒倒计时
    print("🎬 录制将在3秒后开始...")
    for i in range(3, 0, -1):
        print(f"⏰ {i}秒...")
        time.sleep(1)
    print("🎬 开始录制！")
    
    if record_keys:
        print("💡 提示：只显示按键操作，每10张截图汇报一次进度")
    else:
        print("💡 提示：静默截图模式，每10张截图汇报一次进度")
    counter = 0
    
    try:
        while True:
            save_path = os.path.join(session_dir, f"{counter}.png")
            # 循环截图时完全静默
            success = screenshot_window_safe(hwnd, save_path, verbose=False)
            
            if success:
                event_count = key_recorder.get_event_count() if key_recorder else 0
                if record_keys and counter % 10 == 0:  # 每10张截图显示一次状态
                    print(f"� 已录制 {counter} 张截图，{event_count} 个按键事件")
            
            counter += 1
            time.sleep(interval)
            
    except KeyboardInterrupt:
        print(f"\n🛑 用户中断，共截取 {counter} 张图片")
        
        # 保存按键录制结果
        if key_recorder:
            key_recorder.stop_recording()
            if key_recorder.get_event_count() > 0:
                key_file = os.path.join(session_dir, "keystrokes.json")
                key_recorder.save_events(key_file)
            else:
                print("📝 没有录制到按键事件")

# ============================================================================
# 主程序入口
# ============================================================================

def main():
    """主程序入口"""
    # 设置DPI感知
    set_dpi_awareness()
    
    parser = argparse.ArgumentParser(
        description="游戏按键录制与回放系统 - 主录制模块",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
使用示例:
  %(prog)s --list                                    # 列出所有窗口
  %(prog)s --title "游戏名" --record-keys             # 录制游戏操作
  %(prog)s --hwnd 0x12345 --record-keys --interval 0.1  # 高频录制
        """
    )
    parser.add_argument("--list", action="store_true", help="列出所有可见窗口")
    parser.add_argument("--title", type=str, help="窗口标题关键词")
    parser.add_argument("--hwnd", type=str, help="窗口句柄(十六进制)")
    parser.add_argument("--interval", type=float, default=2.0, help="截图间隔(秒)")
    parser.add_argument("--pictures", type=str, default="pictures", help="图片保存目录")
    parser.add_argument("--record-keys", action="store_true", help="同时录制按键和鼠标操作")
    
    args = parser.parse_args()
    
    if args.list:
        list_windows()
        return
    
    if not args.title and not args.hwnd:
        print("请指定 --title 或 --hwnd 参数")
        return
    
    hwnd = None
    if args.hwnd:
        try:
            hwnd = int(args.hwnd, 16)
        except ValueError:
            print(f"无效的窗口句柄: {args.hwnd}")
            return
    elif args.title:
        hwnd = find_hwnd_by_title(args.title)
        if not hwnd:
            print(f"未找到包含 '{args.title}' 的窗口")
            return
    
    print(f"🎯 找到目标窗口: {get_window_title(hwnd)} (HWND: {hex(hwnd)})")
    
    if args.record_keys:
        print("⌨️ 启用按键录制功能（轮询模式）")
    
    # 激活窗口到前台
    print("🔄 激活窗口到前台...")
    bring_to_front(hwnd)
    
    # 运行截图循环
    run_screenshot_loop(hwnd, args.interval, args.pictures, args.record_keys)

if __name__ == "__main__":
    main()
